package guda.house.biz.bo.impl;

import guda.house.biz.bo.EstateFeeBO;
import guda.house.biz.query.BuildingQuery;
import guda.house.biz.query.EstateRuleQuery;
import guda.house.biz.query.SuiteQuery;
import guda.house.biz.query.UnitQuery;
import guda.house.biz.util.PriceUtil;
import guda.house.biz.util.Transform;
import guda.house.biz.util.TransformHelper;
import guda.house.dal.dao.*;
import guda.house.dal.dataobject.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * Created by well on 15/11/16.
 */
public class EstateFeeBOImpl implements EstateFeeBO {
    private final static Logger logger = LoggerFactory.getLogger(EstateFeeBOImpl.class);
    @Autowired
    private EstateDAO estateDAO;
    @Autowired
    private BuildingDAO buildingDAO;
    @Autowired
    private UnitDAO unitDAO;
    @Autowired
    private SuiteDAO suiteDAO;
    @Autowired
    private TransactionTemplate transactionTemplate;
    @Autowired
    private EstateRuleDAO estateRuleDAO;
    @Autowired
    private BillEstateDAO billEstateDAO;

    @Override
    public String stateFee(Long villageId) {

        BuildingQuery buildingQuery = new BuildingQuery();
        buildingQuery.setPageSize(10000);
        buildingQuery.setVillageId(villageId);

        List<BuildingDO> buildingDOs = buildingDAO.selectForPage(buildingQuery);
        buildingQuery.setPageSize(10000);
        List<Long> buildingIdList = TransformHelper.transform(buildingDOs, new Transform<BuildingDO, Long>() {
            @Override
            public Long transform(BuildingDO object) {
                return object.getBuildingId();
            }
        });
        final Map<Long, BuildingDO> buildingDOMap = new HashMap<Long, BuildingDO>(buildingIdList.size() * 2);
        for (BuildingDO buildingDO : buildingDOs) {
            buildingDOMap.put(buildingDO.getBuildingId(), buildingDO);
        }

        UnitQuery unitQuery = new UnitQuery();
        unitQuery.setBuildingIdList(buildingIdList);
        unitQuery.setPageSize(10000);
        List<UnitDO> unitDOs = unitDAO.selectForPage(unitQuery);
        List<Long> unitIdList = TransformHelper.transform(unitDOs, new Transform<UnitDO, Long>() {
            @Override
            public Long transform(UnitDO object) {
                return object.getUnitId();
            }
        });
        final Map<Long, UnitDO> unitDOMap = new HashMap<Long, UnitDO>(unitDOs.size() * 2);
        final Map<Long, Long> unitMap = new HashMap<Long, Long>(unitDOs.size() * 2);
        for (UnitDO unitDO : unitDOs) {
            unitMap.put(unitDO.getUnitId(), unitDO.getBuildingId());
            unitDOMap.put(unitDO.getUnitId(),unitDO);
        }

        EstateRuleQuery estateRuleQuery = new EstateRuleQuery();
        estateRuleQuery.setVillageId(villageId);
        List<EstateRuleDO> estateRuleDOs = estateRuleDAO.selectForView(estateRuleQuery);
        final Map<Long, EstateRuleDO> estateRuleDOMap = new HashMap<Long, EstateRuleDO>(20);
        for (EstateRuleDO estateRuleDO : estateRuleDOs) {
            estateRuleDOMap.put(estateRuleDO.getVarId(), estateRuleDO);
        }

        SuiteQuery suiteQuery = new SuiteQuery();
        suiteQuery.setUnitIdList(unitIdList);
        suiteQuery.setPageSize(10000);
        final List<SuiteDO> suiteDOs = suiteDAO.selectForPage(suiteQuery);
        final List<String> unDelivery = new ArrayList<String>();
        final List<String> unReady = new ArrayList<String>();
        final List<String> unRule = new ArrayList<String>();
        final List<String> stated = new ArrayList<String>();
        final List<String> statSucess = new ArrayList<String>();
        final StringBuilder errorBuf = new StringBuilder();
        final StringBuilder statedBuf = new StringBuilder();
        final StringBuilder buf = new StringBuilder();
        //获取统计年度
        Calendar statCalendar = Calendar.getInstance();
        final int statYear = statCalendar.get(Calendar.YEAR);
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus transactionStatus) {

                for (SuiteDO suiteDO : suiteDOs) {
                    UnitDO unitDO = unitDOMap.get(suiteDO.getUnitId());
                    Long aLong = unitMap.get(suiteDO.getUnitId());
                    BuildingDO buildingDO = buildingDOMap.get(aLong);
                    if(suiteDO.getGmtDelivery() == null){
                        logger.warn("stat-estate-warn:" + buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",没有设置交付时间，无法统计物业费");
                        errorBuf.append(buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",没有设置交付时间，无法统计物业费").append("\n");
                        continue;
                    }

                    EstateRuleDO estateRuleDO = estateRuleDOMap.get(suiteDO.getBuildingTypeId());
                    if (estateRuleDO == null) {
                        logger.warn("stat-estate-warn:" + buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",没有计费规则，无法统计物业费");
                        errorBuf.append(buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",没有计费规则，无法统计物业费").append("\n");
                        unRule.add(suiteDO.getSuiteName());
                        continue;
                    }
                    List<Date> statMonth = getStatMonth(suiteDO.getSuiteId());
                    if (statMonth.size() == 0) {
                        stated.add(suiteDO.getSuiteName());
                        logger.warn("stat-estate-warn:" + buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",年度［" + statYear + "］的物业费已经生成，无需再次生成");
                        statedBuf.append(buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + ",年度［" + statYear + "］的物业费已经生成，无需再次生成").append("\n");
                        continue;
                    }
                    Long suiteArea = suiteDO.getSuiteArea();
                    Long feeUnit = estateRuleDO.getFeeUnit();
                    long totalFee = suiteArea * feeUnit / 1000;//单位为分
                    Calendar temp = Calendar.getInstance();
                    for (Date s : statMonth) {
                        temp.setTime(s);
                        int month = temp.get(Calendar.MONTH) + 1;
                        int year = temp.get(Calendar.YEAR);
                        BillEstateDO billEstateDO = new BillEstateDO();
                        billEstateDO.setSuiteId(suiteDO.getSuiteId());
                        billEstateDO.setIsPayed(0);
                        billEstateDO.setRecordYear(statYear);
                        billEstateDO.setRecordYear(year);
                        billEstateDO.setRecordMonth(month);
                        billEstateDO.setPayTotal(totalFee);
                        billEstateDO.setGmtEnd(temp.getTime());
                        Calendar calendarStart = Calendar.getInstance();
                        calendarStart.setTime(s);
                        calendarStart.add(Calendar.MONTH, -1);
                        billEstateDO.setGmtStart(calendarStart.getTime());
                        billEstateDAO.insert(billEstateDO);
                        statSucess.add(suiteDO.getSuiteName());
                        logger.info("stat-estate-warn:" + buildingDO.getBuildingName() + "幢" + unitDO.getUnitName() + "单元房号:" + suiteDO.getSuiteName() + "，年度:" + year + ",月份:" + month + ",物业费:" + PriceUtil.formatCNY(totalFee) + "元");
                        buf.append(buildingDO.getBuildingName() + "幢" + aLong + "单元房号:" + suiteDO.getSuiteName() + "，年度:" + year + ",月份:" + month + ",物业费:" + PriceUtil.formatCNY(totalFee) + "元,已经生成").append("\n");

                    }


                }

            }
        });

        StringBuilder result = new StringBuilder();
        result.append("本小区共有").append(suiteDOs.size()).append("户").append("\n")
                .append("共有").append(statSucess.size()).append("户成功生成物业费账单.").append("\n")
                .append("共有").append(unDelivery.size()).append("户由于没有设置交付时间，无法生成账单.").append("\n")
                .append("共有").append(unRule.size()).append("户没有计费规则，无法生成账单").append("\n")
                .append("共有").append(unReady.size()).append("由于时间未到，无需生成账单").append("\n");
        result.append("详细信息:").append("\n");
        result.append(errorBuf).append("\n");

        result.append(statedBuf).append("\n");

        result.append(buf).append("\n");

        return result.toString();

    }

    //获取需要统计得月份
    private List<Date> getStatMonth(Long suiteId) {
        List<Date> list = new ArrayList<Date>();
        BillEstateDO billEstateDO1 = billEstateDAO.selectLatest(suiteId);
        Calendar statCalendar = Calendar.getInstance();
        int statYear = statCalendar.get(Calendar.YEAR);
        int statmonth = statCalendar.get(Calendar.MONTH);
        SuiteDO suiteById = suiteDAO.getSuiteById(suiteId);
        Date gmtDelivery = suiteById.getGmtDelivery();

        Calendar deliveryCal = Calendar.getInstance();
        deliveryCal.setTime(gmtDelivery);
        int deliveryMonth = deliveryCal.get(Calendar.MONTH);
        if (deliveryMonth <= statmonth) {
            statYear = +statYear + 1;
        }
        statCalendar.set(Calendar.YEAR, statYear+1);
        statCalendar.set(Calendar.MONTH, deliveryMonth - 1);
        if (billEstateDO1 == null) {
            while (deliveryCal.getTime().before(statCalendar.getTime())) {
                deliveryCal.add(Calendar.MONTH, 1);
                list.add(deliveryCal.getTime());
            }
        } else {

            Calendar deliveryCal2 = Calendar.getInstance();
            deliveryCal2.setTime(billEstateDO1.getGmtEnd());
            while (deliveryCal2.getTime().before(statCalendar.getTime())) {
                deliveryCal2.add(Calendar.MONTH, 1);
                list.add(deliveryCal2.getTime());
            }
        }
        return list;
    }

    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();
        Calendar statCalendar = Calendar.getInstance();
        int statYear = statCalendar.get(Calendar.YEAR);
        int statmonth = statCalendar.get(Calendar.MONTH);
        String deliveryDate = "2015-12-19";
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");

        Date gmtDelivery = null;
        try {
            gmtDelivery = format.parse(deliveryDate);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        Calendar deliveryCal = Calendar.getInstance();
        deliveryCal.setTime(gmtDelivery);
        int deliveryMonth = deliveryCal.get(Calendar.MONTH);
        if (deliveryMonth <= statmonth) {
            statYear = +statYear + 1;
        }
        System.out.println(deliveryMonth);
        statCalendar.set(Calendar.YEAR, statYear+1);
        statCalendar.set(Calendar.MONTH, deliveryMonth - 1);
        while (deliveryCal.getTime().before(statCalendar.getTime())) {
            deliveryCal.add(Calendar.MONTH, 1);
            SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
            list.add(simpleDateFormat.format(deliveryCal.getTime()));
        }

        for (String s : list) {
            System.out.println(s);
        }

    }
}
